<?php
declare (strict_types = 1);

namespace command\controller;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

class ControllerCreate extends Command
{

    protected $tplStr = [];

    protected function configure()
    {
        // 指令配置
        $this->setName('controller:create')
            ->addArgument('module', Argument::OPTIONAL, "app module name")
            ->addOption('controllers', null, Option::VALUE_REQUIRED, 'op controllers list')
            ->setDescription('auto create logic');        
    }

    protected function execute(Input $input, Output $output)
    {
        $module = $input->getArgument('module');

        //获取项目配置，根据项目配置写入接口方法
        $projectFile = $this->app->getBasePath().DIRECTORY_SEPARATOR.'Project.php';
        if(is_file($projectFile)){
            $projectConfig = include_once $projectFile;
            $controllerConfigList = $module?($projectConfig[$module]['controller']??[]):($projectConfig['controller']??[]);
        }else{
            $controllerConfigList = [];
        }

        if(empty($controllerConfigList)){
            $output->writeln('controller config is empty');
            return true;
        }

        $modulePath = $module?$module."/":'';

        if ($input->hasOption('controllers')) {
            $controllers = $input->getOption('controllers');
            $controllers = explode(',',$controllers);
        }else{
            $controllers = [];
        }


        $path = $this->app->getBasePath().$modulePath."controller";

        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }

        $stub = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'controller.stub');

       
        foreach ($controllerConfigList as $controllerName => $config) {

            $namespace = 'app\controller';

            if($module)$namespace = 'app\\'.$module.'\controller';

            $pathName = $path . DIRECTORY_SEPARATOR . $controllerName .".php";

            if(is_file($pathName))continue;//文件已存在跳过

            $method = $this->buildMethod($config['methods'],$config['comment']);

            file_put_contents(
                $pathName,
                str_replace(
                    ['{$namespace}','{$use}','{$comment}','{$controllerName}','{$controllerMethod}','{$exceptLogin}','{$apiCat}'],
                    [$namespace,$method['use_str'],$config['comment'],$controllerName,$method['method_str'],$config['except_login']??'',$config['api_cat']??''],
                    $stub
                )
            );

        }

    	// 指令输出
    	$output->writeln('controller');
    }

    /**
     * 构建逻辑处理方法
     *
     * @param array $modelConfig
     * @param string $modelName
     * @return void
     */
    private function buildMethod($methodList,$classComment)
    {
        $use = [];
        $functions = [];

        $publicTpl = $this->getMethodTpl('public');

        $methodList = $this->buildMethodConfig($methodList);

        foreach ($methodList as $methodName=>$config) {
            $use[]='use '.($config['call_namespace']??'app\\logic').'\\'.$config['call_logic'].';';

            $validate = $this->buildValidate($config['param']);;
            if($validate){
                $validateStr = $this->getMethodTpl('validate');
                $validate = str_replace('{$validate}',$validate,$validateStr);
            }

            $methodStr = $this->getMethodTpl($config['call_type']);

            $callMethod = str_replace(['{$callMethod}','{$pk}','{$with}','{$order}'],[$config['call_method'],$config['call_pk'],$config['with']??'""',$config['order']??'""'],$methodStr);
            $functions[]=str_replace(
                ['{$comment}','{$route}','{$reqMethod}','{$param}','{$apiCat}','{$methodName}','{$validate}','{$callLogic}','{$callMethod}'],
                [$config['comment'],$config['route'],$config['req_method'],$config['param'],$config['api_cat']??$classComment,$methodName,$validate,$config['call_logic'],$callMethod],
                $publicTpl
            );
            
        }

        $res['method_str'] = implode(PHP_EOL.PHP_EOL,$functions);
        $res['use_str'] = implode(PHP_EOL,array_unique($use));

        return $res;

    }

    /**
     * 自动构建项目配置
     *
     * @param array $methodList
     * @return array
     */
    private function buildMethodConfig($methodList)
    {
        $reqMethod = [
            'add'=>'post',
            'list'=>'get',
            'update'=>'post',
            'delete'=>'post',
            'info'=>'get',
            'find'=>'get'
        ];

        $newList = [];
        foreach ($methodList as $name => $config) {
            if(empty($config['logic_list'])){
                $newList[$name] = $config;
                continue;
            }
            foreach ($config['logic_list'] as $type => $value) {
                $temp = [
                    'comment'=>$this->buildComment($config['comment'],$type),
                    'call_logic'=>$config['call_logic'],
                    'call_method'=>($config['method_prefix']??$name).ucfirst($type),
                    'call_type'=>$type,
                    'route'=>empty($value['route'])?'/'.strtolower($name).'/'.$type:$value['route'],
                    'req_method'=>$reqMethod[$type]
                ];
                $pub = $config;
                unset($pub['logic_list']);
                $newList[$name.ucfirst($type)]=array_merge($pub,$value,$temp);
            }
        }

        return $newList;
    }

    /**
     * 获取代码块模板
     *
     * @param string $name
     * @return string
     */
    private function getMethodTpl($name)
    {
        if(empty($this->tplStr[$name])){
            $tplFile = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'method' . DIRECTORY_SEPARATOR . $name . '.stub';
            if(is_file($tplFile)){
                $this->tplStr[$name]=file_get_contents($tplFile);
            }else{
                return false;
            }
        }

        return $this->tplStr[$name];
    }

    /**
     * 通过参数构建必填验证
     *
     * @param string $paramstr 参数字符串
     * @return string
     */
    private function buildValidate($paramstr)
    {
        $validate = [];

        foreach (explode(',',$paramstr) as $key => $value) {
            $set = explode('|',$value);
            if(!empty($set[1])&&$set[1]==1){
                $validate[] = '"'.$set[0].'|'.$set[2].'"=>"require"';
            }
        }

        if(empty($validate))return '';

        return '['.implode(',',$validate).']';
    }

    /**
     * 构建备注
     *
     * @param [type] $comment
     * @param [type] $reqMethod
     * @return string
     */
    private function buildComment($comment,$reqMethod)
    {
        switch ($reqMethod) {
            case 'add':
                return '添加'.$comment;
                break;
            case 'list':
                return $comment.'列表';
                break;
            case 'update':
                return '更新'.$comment;
                break;
            case 'delete':
                return '删除'.$comment;
                break;
            case 'info':
                return $comment.'详情';
                break;
            case 'find':
                return '查询'.$comment;
                break;
            default:
                return $comment;
                break;
        }
    }
}
